home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Help / Extending Alpha < prev    next >
Encoding:
Text File  |  2000-11-16  |  67.4 KB  |  1,592 lines

  1.  
  2.             Writing New Modes, Menus and Packages
  3.  
  4.  
  5.                                               created: 97-03-03 11.44.50
  6.                                           last update: 11/16/2000 {12:34:04 PM}
  7.  
  8. Author:    Vince Darley, some pieces by Tom Fetherston and Pete Keleher
  9. E-mail:    <vince@santafe.edu>
  10.   mail:    317 Paseo de Peralta, Santa Fe, NM 87501, USA
  11.    www:    <http://www.santafe.edu/~vince/>
  12.  
  13.  
  14.            Introduction
  15.  
  16. This document tells you how to write or modify code to add functionality 
  17. to Alpha or Alphatk.  Alpha 7.x, 8.x and Alphatk all rely upon the
  18. AlphaTcl library to perform most tasks.  The AlphaTcl library in turn
  19. provides an API (a set of procedures, variables, interfaces) by which 
  20. you can add new features.  If written correctly, such additions will
  21. work seamlessly with any of Alpha 7.x, 8.x or Alphatk.
  22.  
  23. Examples of such additions may be to create a new mode, menu, add an
  24. item to an existing mode or menu, or simply add some missing
  25. functionality.  Collectively all of these things are known as
  26. 'packages' or 'features'.  Individual packages may be referred to as
  27. modes, menus or extensions depending upon their use.
  28.  
  29. This document also tells you how to make your package interact effectively 
  30. with a few other commonly used packages which users might already be using.
  31.  
  32. There are two basic types of package which Alpha uses: modes, and 
  33. features.  A mode helps with editing a file for a particular purpose: 
  34. web pages use 'HTML' mode, C++ code uses 'C++' mode, LaTeX documents 
  35. use 'TeX' mode,… There are about 40 such modes currently available.  
  36. Features are of three types: menus, extensions and ordinary features.  
  37. A feature adds functionality to Alpha either globally (a 'global 
  38. feature') or just for particular modes (a 'mode feature').  Menus are 
  39. one type of feature used to extend Alpha, and aren't really much different 
  40. to features which don't add menus: the only distinguishing difference is a 
  41. couple of lines of code which do some menu creation/deletion. 
  42.  
  43. Here are some examples:
  44.  
  45.     alpha::extension recentFilesMenu 0.4 ...
  46.  
  47. The menu of recent files, accessible from Alpha's File menu is an
  48. extension.  Extensions can only be turned on and off globally, which makes
  49. sense for this package, since a user will either want to have access to the
  50. menu all the time, or not at all.  The number is the version of this
  51. package; in this case version 0.4.  Notice this is declared as an
  52. extension, not as a menu.  The 'alpha::menu' command is reserved for menus 
  53. which appear in Alpha's menubar, not submenus such as this.
  54.  
  55.     alpha::feature latexAccents 1.0.5 {TeX Bib} ...
  56.  
  57. Some users of LaTeX find it easier to type accented characters 'éåü…'
  58. directly into their documents rather than somewhat esoteric control codes
  59. like \'{e}.  This package makes that task a lot easier.  It is only useful
  60. for LaTeX and BibTeX documents, so the author specifies that information in
  61. an extra argument to 'alpha::feature' which is not allowed (or relevant)
  62. for 'alpha::extension'.
  63.  
  64. Most modes add a menu which is automatically attached to that mode.  Other
  65. menus are often useful globally.  It's up to the user to decide when each
  66. feature/menu is active, although each feature can specify its default. 
  67. Mode-authors can of course set the defaults for their mode.  Examples of
  68. globally useful menus are the filesets menu, the eudora menu and the
  69. electric menu.  When you create a new menu for Alpha, you have the option
  70. of suggesting that it is attached to particular modes, or that it is
  71. suggested as global, or that it is global only.  General features are
  72. organised in the same way, but don't create menus.  Finally, an extension
  73. is a simple form of feature which is either globally active or off (it
  74. either doesn't make sense or isn't particuarly useful to turn extensions on
  75. and off in a mode-dependent way).  Examples of extensions are the printer
  76. choices sub-menu, or the bib-engine (used to interact with BibTeX).  Note:
  77. a 'menu' is something which sits in Alpha's menubar, at the top level.  A
  78. feature or extension can create submenus which sit inside top level menus,
  79. but these are not 'menus' in the same sense.  The main distinction is that
  80. menus must be registered with 'alpha::menu' or 'addMenu', whereas submenus
  81. need no special registration.
  82.  
  83. For the impatient reader: here's how to write a very simple feature 
  84. which contains one new procedure and one new key-binding (to that 
  85. procedure).  Just create a file which looks like this:
  86.  
  87.     # (auto-install) --- this line will cause Alpha to try to install 
  88.     # this pkg when this file is opened outside of Alpha's folder hierarchy
  89.     
  90.     alpha::feature myPackage 0.1 {C C++} {
  91.         # no global initialisation required
  92.     } {
  93.         # activation script
  94.         # bind the 'x' key to my procedure (not a good idea ;-)
  95.         Bind 'x' myProcedure
  96.     } {
  97.         # deactivation script
  98.         unBind 'x' myProcedure
  99.     } uninstall {this-file} maintainer {
  100.         "My Name" my@email http://webpage..
  101.     } help {
  102.         Binds the blah-key to 'myProcedure' which carries out...
  103.         
  104.         This package is only designed to do something useful in
  105.         C and C++ modes.
  106.     }
  107.     
  108.     proc myProcedure {} {
  109.         # do some cool stuff
  110.     }
  111.     
  112. Save this file on your desktop (say), and open it.  You'll see Alpha
  113. automatically opens an installation dialog, puts this file in the
  114. right place if you agreed to the installation, and rebuilds its
  115. package and tcl indices so that this package can be used next time
  116. you restart Alpha (actually with a simple package like this, you can
  117. use it straight-away).  By default this package declares it is useful
  118. for C and C++ modes, although the user could choose to activate the
  119. package globally or individually for any set of modes.
  120.  
  121. Important note: if you're writing a mode, menu or package, you should 
  122. know about the 'package index'.  Alpha keeps a cache of all startup 
  123. information, so that if you edit your 'alpha::mode ...' statement, and 
  124. quit and restart Alpha, the changes will not take effect.  You must
  125. tell Alpha to rebuild the package indices before quitting.
  126.  
  127. Alpha provides lots of cool facilities to help you write useful
  128. packages, whether they are modes, menus or extensions.  This
  129. document describes those facilities.
  130.  
  131.              Guidelines for future compatibility
  132.  
  133. This section is useful if you're concerned about making future transitions
  134. easier.  Since Alpha will be upgraded to Tcl 8 for the next major release
  135. (no date yet!), knowing this will save you trouble later.  It will also
  136. help you to understand how to write code which works efficiently with Tcl
  137. 8, making maximum use of the potential speed improvements there.
  138.  
  139. When Alpha upgrades to Tcl 8, some changes to your code may be necessary, 
  140. unless you pay attention to a few simple details.  
  141.  
  142.                Namespaces
  143.  
  144. First, any proc which contains '::' is a procedure defined inside a
  145. namespace.  Tcl 8 requires you to declare namespaces in advance.  Hence
  146. unless Tcl 8 knows about namespace 'A', say, defining a procedure 'proc
  147. A::blah ...'  is an error.  You should therefore include the line
  148. 'namespace eval A {}' at the beginning of the file defining all the 'A::'
  149. procedures.  (Alpha 7.2 will ignore these namespace commands so your code
  150. works either way)
  151.  
  152.                Namespaces and infinite loops
  153.  
  154. The second guideline concerns the way namespaces actually work.
  155. Assume you have defined two procedures 'A::open' and 'A::list'.
  156. Let's say: 
  157.  
  158.     proc A::list {} { open [file join $HOME Help Changes] w ; ...}
  159.     proc A::open {} { return [list a b c] }
  160.  
  161. Then both of these procedures will fail (and may crash Alpha) if 
  162. running Tcl 8.  This is because inside the procedures we're in the 'A' 
  163. namespace and this means commands are checked first to see if they 
  164. exist inisde that namespace.  Therefore command 'open' in A::list is 
  165. not the global Tcl command 'open', rather it is the procedure A::open 
  166. (obviously not what was intended above).  Similarly 'list' in A::open 
  167. is in fact the procedure A::list.  There are two ways to resolve this: 
  168. (i) write 'list' as '::list' inside the proc (and 'open' as '::open'), 
  169. or (ii) ensure the tail end of your procedures do not clash with any 
  170. global Tcl commands.  The first option will not work in Tcl earlier 
  171. than 8.0, which means you'd have to supply two different definitions 
  172. of the procedure and use 'if {[info tclversion] < 8.0} ...'  to create 
  173. the correct one.  The second option will work without modification, 
  174. and is therefore somewhat preferable.
  175.  
  176.                Variable-parameter name clashes
  177.  
  178. A third problem occurs quite rarely.  A variable such as 'index::flags'
  179. is actually a variable 'flags' inside a namespace 'index'.  Under some
  180. circumstances it is possible for a nameclash to occur.  For instance:
  181.  
  182.     proc test {flags} {
  183.         global index::flags
  184.         ...
  185.     }
  186.  
  187. Will throw an error 'Error: variable "flags" already exists' when
  188. executed.  The easy solution is to rename the parameter passed in
  189. (from flags to theFlags or whatever).  Name clashes can only happen
  190. between function parameters and variables declared inside.  Note
  191. that this behaviour is simply an extension of the more obvious
  192. mistake in Tcl 7.x of 'proc test {flags} { global flags ... }'.
  193.  
  194.                Directory delimiters
  195.  
  196. MacOS uses the colon ':' as a directory delimiter, so paths in Alpha
  197. may be written as $HOME:Tcl:SystemCode:...  However, with the
  198. forthcoming release of Mac OS X, the OS will have a unix underpinning,
  199. and Alpha will use the MacOS X-native version of Tcl, which is
  200. similarly unix based.  Hence the Tcl library within Alpha will then
  201. use the forward-slash '/' as a directory delimiter.  The simple
  202. solution is to use 'file join' 'file split' and ${file::separator} so 
  203. that you don't assume any particular delimiter, and your code works
  204. fine on all platforms.  The same issue arises with Alphatk
  205. compatibility.
  206.  
  207.                Other Tcl 8.x details
  208.  
  209. A final Tcl 8 issue is that lists are not parsed lazily as in Tcl 7.x.
  210. So, grabbing an arbitrary string and doing 'lindex $string 0' in Tcl
  211. 7.x will usually return the first element of $string without an error,
  212. even if $string is not a valid Tcl list (e.g. it contains unmatched {}
  213. braces).  In Tcl 8 the entire string is first converted to a list, and
  214. then the first element is extracted.  If the string is not a list, an
  215. error will result.  The solution is only to use 'lindex/lrange/etc'
  216. where you really have a list, and to use 'split' or 'regexp' or the
  217. various 'string' commands when you need to manipulate strings.  For
  218. example 'regexp "^\[^ \t\r\n\]+" $string firstElement' will usually
  219. accomplish the same as 'lindex $string 0' (beware if $string may start 
  220. with whitespace; you need a more complex regular expression).
  221.  
  222. By following these two guidelines, your code should continue to work
  223. without any changes _at all_, when Alpha upgrades (except that your
  224. code will run 2-10 times faster!).
  225.  
  226. If you're really concerned about maximum efficiency in Tcl 8, make
  227. sure you always use '{}' with both 'if' and 'expr'.  This speeds things
  228. up with Tcl 8 due to some technical aspects of the way the Tcl compiler
  229. works (see http://www.scriptics.com for details).  For example don't
  230. write 'if [expr 1+2 == 3] ...' but rather 'if {[expr {1+2 == 3}]}'.
  231.  
  232. A very important pointer for speed in Tcl 8 is that lists are very fast.
  233. This means using 'lappend', 'lindex' etc is very quick.  There is one
  234. small point you should obey: never use 'if {$myList == ""} {...}' to see
  235. if a list is empty.  Instead use 'if {![llength $myList]} {...}'.  Until
  236. Tcl implements some good optimisation in the internal compiler (which it
  237. may never do), the former expression will slow your code down hugely when
  238. the list isn't empty.
  239.  
  240. The behaviour of [file tail] has changed slightly between Tcl 7.5 (as used
  241. by Alpha 6.x and 7.x) and 8.0; with 7.5 [file tail a:b:] was "", but 8.0
  242. returns "b".  Try to write code which doesn't depend on this distinction.
  243.  
  244. The commands 'bind', 'menu', 'unbind' etc.  and all procedures in the
  245. BackCompatibility.tcl file are obsolete.  Please do not use them.  At
  246. some point in the future they will be removed completely.  In
  247. particular you should realise that the compatibility procedures are
  248. slower than calling the correct ones (especially 'menu' --- use 'Menu'
  249. instead), so you might as well go through the effort of modernising
  250. your code now.  In addition there have been many, many improvements and
  251. bug fixes to Alpha since 7.0/7.1/7.2, so you'll save your end-user,
  252. yourself and the Alpha-D list a lot of trouble if everyone is
  253. encouraged to upgrade to Alpha 7.3 or newer.
  254.  
  255.              Guidelines for Alphatk compatibility
  256.  
  257. Related to the above is the recent release of Alphatk, a version of
  258. Alpha which runs on Unix and Windows using the Tk toolkit.  If you want
  259. your packages to function smoothly with Alphatk, make sure you obey
  260. the following guidelines.  As an added benefit, if the windowing model
  261. in Alpha changes in the future, if you follow these guidelines, your
  262. code will still work.
  263.  
  264. Positions in Alphatk are not necessarily integers, in fact they may
  265. contain all sorts of stuff (e.g. '5.0 lineend wordstart' is a valid
  266. position in Alphatk).  Hence you can't use 'expr' to add/subtract
  267. positions since they aren't numbers.  Also, since they may contain
  268. spaces, you must be careful with 'concat', 'eval' etc which may break
  269. them apart into multiple arguments (e.g. don't do something like 'eval
  270. goto $pos').  Alpha provides the following 4 functions which you can use
  271. instead, and which provide all the functionality you need (see "Alpha
  272. Commands" for details):
  273.  
  274.     pos::math
  275.     pos::compare
  276.     pos::diff
  277.     minPos
  278.  
  279. Provided you use these functions, your code will work unchanged across 
  280. Alpha 7.x, Alpha 8.x and Alphatk.  There are a few subtleties concerning
  281. the beginning and end of the window and the behaviour of the above 
  282. commands when dealing with positions which don't exist (because they are 
  283. before the beginning or after the end of the window).  In these cases,
  284. the behaviour may vary between Alpha 7.x, 8.x and Tk.  If this becomes
  285. a problem, we will fix things...
  286.  
  287.              Declaring your package to Alpha
  288.  
  289. A package must contain, preferably as its first non-comment line (this 
  290. is important), a statement like this:
  291.  
  292.     alpha::mode NAME VERSION ...
  293.     
  294.     alpha::menu NAME VERSION ...
  295.     
  296.     alpha::feature NAME VERSION ...
  297.     
  298.     alpha::extension NAME VERSION ...
  299.     
  300. (The other parameters to these commands are explained below).  The name will 
  301. identify your package, and for modes must be at most 4 characters long.  
  302. It should not contain any spaces (this limitation may be lifted in a future 
  303. version of Alpha).  The version is a string of the form 1.0.1, or 2.3b1 or 
  304. 1.4.530.1.3a5.  Modes, menus and extensions take different arguments for the 
  305. remainder of the 'alpha::' declaration line, but each ends in a script which 
  306. Alpha scans and stores for you (Alpha scans all installed files for 
  307. package declaration lines and caches this information so that at startup, 
  308. no files need be read).  For modes and menus, this script is executed 
  309. automatically at startup.  For features, there are initialisation and 
  310. activation/deactivation scripts.  An extension is a simpler form of a 
  311. feature which only has a single initialisation script (used the first 
  312. time it is activated).  Package initialization occurs in the order: modes, 
  313. menus and finally extensions.
  314.  
  315. IMPORTANT: The declaration command must not be wrapped in any 'catch' 
  316. statements.  This is necessary to allow Alpha to rebuild package 
  317. indices rapidly (note that it is no longer required to be at the 
  318. beginning of the line).  If you wish to write backwards compatible code, 
  319. try something like:
  320.  
  321.     if {[info commands alpha::extension] != ""} {
  322.         alpha::extension ...
  323.     } else {
  324.         # initialize in some old way for Alpha 6.x
  325.     }
  326.  
  327. Your package will not function properly if you don't obey the above 
  328. guidelines.  Alpha itself is considered a package, with a version
  329. number, so that your code can request a particular version of Alpha.
  330. Alpha's version number also has a patchlevel which will be updated
  331. with each Tcl-only patch release.  Hence you can write:
  332.  
  333.     alpha::package require Alpha 7.1b1
  334.  
  335. For the first Alpha 7.1 beta release, and
  336.  
  337.     alpha::package require Alpha 7.1p1
  338.  
  339. If your package actually requires some fixes from the first patch 
  340. release after the final 7.1 release.  You can similarly require 
  341. particular versions of other packages.  You should 'require' as old a 
  342. version as possible, so that you don't force users to upgrade 
  343. unnecessarily.
  344.  
  345. Note that with the advent of the new alpha:: commands, it is no longer
  346. necessary to place modes, menus and packages in their separate directories:
  347. they can go anywhere on the auto-path.  However it is more convenient to
  348. store them separately most of the time.
  349.  
  350.              The Alpha developer menu
  351.  
  352. You will want to activate/download this menu, since it helps with a 
  353. number of developer-related tasks:
  354.  
  355. •    distribution archival, compression, and uploading
  356. •   creation of new modes/menu/features/extensions
  357. •    colouring and hyperlinking Help files (like this one)
  358.  
  359. For anyone helping with Alpha's core distribution it also allows:
  360.  
  361. •    colouring Alpha's manual, commands, readme and changes files
  362.  
  363.              Licensing issues
  364.  
  365. Obviously if you want to allow your code to be distributed with Alpha
  366. and/or Alphatk, you need to license it under a compatible license
  367. agreement -- one that allows free redistribution of your code.  The
  368. most obvious choices are a 'Tcl/Tk/BSD' style license or a 'GNU' style
  369. license, although other licenses are possible.  If your Tcl code is of
  370. use with Tcl/Tk in general (i.e. not restricted to being used inside
  371. Alpha/Alphatk), then you are strongly urged to use a Tcl-compatible
  372. license, not a GNU license, since that is the norm in the Tcl
  373. community.  Alpha and Alphatk come with various pieces of code
  374. copyrighted and licensed under both of these licenses.
  375.  
  376. ===============================================================================
  377.            
  378.            Writing New Modes
  379.  
  380. To add a mode to Alpha, a file (usually ending with 'Mode.tcl') must be 
  381. created and placed in the ":Tcl:Modes" directory.  Please note that
  382. the 'standard' tab size to be used in AlphaTcl is 8.  Of course
  383. individuals can use whatever they want, but most existing code uses a 
  384. tab-size of 8 (with an indentation amount of 4).
  385.  
  386. The file should begin with a construct of the following form:
  387.  
  388.     alpha::mode Perl 1.3 dummyPerl {*.pl *.ph *.pm} {
  389.         perlMenu electricBraces electricReturn 
  390.     } {
  391.         addMenu perlMenu •132 Perl
  392.     }
  393.  
  394. This command is very, very important.
  395.  
  396.     alpha::mode <mode> <version> <startupScript> <suffixes> <mode-features> <script>
  397.     
  398. defines a new mode.  The first time Alpha tries to switch to Perl mode,
  399. the 'startupScript' will be evaluated.  In this case this is the procedure
  400. 'dummyPerl'.  This procedure is simply an empty procedure in the main
  401. perlMode.tcl file.  The effect of evaluating it is to first autload that
  402. procedure: i.e. source the perlMode.tcl file.  Having done that the actual
  403. procedure evaluation is rather irrelevant: hence the name 'dummyPerl'.
  404. Subsequent switches to Perl mode will not need to sourced the file, and
  405. in fact as of AlphaTcl 7.4, the startup script is only ever evaluated once.
  406. As a simplification, you can use the word 'source' as a startupScript,
  407. and AlphaTcl will source the file in which the alpha::mode statement
  408. occurs.
  409.  
  410. The 'suffixes' allow Alpha to automatically determine the correct mode of a 
  411. newly opened file.  In this case the script contains the single command:
  412.  
  413.     addMenu <mname> ?<name>? ?<pertains to modes>?
  414.  
  415. which defines a new menu, with 'name' the visible name of the menu (names 
  416. which start with '•' indicate Alpha should use an icon resource with the 
  417. given number.  Icon number 132 is the Perl camel icon).  This menu can be 
  418. used in any mode, although by default, it is only attached to Perl mode.  
  419. 'mname' is actually a variable which contains (will contain) the real menu 
  420. name (in this case '•132').  The third argument usually contains a 
  421. single mode with which this menu is distributed.  Its use is mainly so that
  422. Alpha knows that this menu belongs primarily to this mode, so that if the user
  423. asks for information on the menu, Alpha knows to respond with 
  424. information on the mode instead (curiously Alpha wouldn't otherwise 
  425. know).
  426.  
  427. Perhaps the MOST important part of the above code is the existence of the
  428. 'startupScript'.  When this proc is called, the result must be that all of
  429. the mode's preferences are declared.  In other words, the startupScript
  430. should ensure that the Tcl code containing all the 'newPref' declarations
  431. is evaluated.  The normal way to do this is to have the 'startupScripts' be
  432. a dummy procedure: e.g. 'proc dummyPerl {} {}' as above.  Tcl's autoloading
  433. mechanism will then source the file containing that procedure.  Hence the
  434. dummy procedure should normally be in the same file as the mode's 'newPref'
  435. declarations.  This is important because almost directly after that call,
  436. Alpha expects all of the mode's preferences to be stored in the
  437. ${mode}modeVars array, which will only be true if all of the newPref
  438. commands have been evaluated.  IMPORTANT subtlety: the result of calling
  439. 'dummyProc/startupScript' must indeed be that all your newPref declarations
  440. are executed.  As a result of this, the preferences will be stored in the
  441. <mode>modeVars array, but will not yet be copied into the global scope
  442. (i.e. the <mode>modeVars(myPref) array element will exist, but the global
  443. var 'myPref' will not yet exist).  Once your dummyProc/startupScript
  444. returns (which generally means your mode's initialisation and sourcing of
  445. files is complete), only then are the array entries copied into the global
  446. scope (in the latter half of the changeMode proc).
  447.  
  448. Here is an example from Diff mode:
  449.  
  450.     alpha::mode Diff 1.0 diffMenu {*.diff} {diffMenu} {
  451.         addMenu diffMenu •288
  452.         menu::insert Utils submenu 0 compare
  453.         menu::insert compare items end "windows" "files…" "directories…"
  454.     } uninstall {
  455.         file delete "$pkg_file"
  456.         file delete [file join ${HOME} Tools "GNU Diff"]
  457.     } maintainer { "Vince Darley" vince@santafe.edu http://... }
  458.  
  459. The 'uninstall' and 'maintainer' sections are optional, and explained later.  
  460. Here is a more complex example for Python mode:
  461.  
  462.     # ◊◊◊◊ minalmalist mode set-up ◊◊◊◊ #
  463.     alpha::mode Pyth 0.2 dummyPython {*.py *.pyc *.pyi} PythonMenu {
  464.         addMenu PythonMenu
  465.         #To set the mode from a unix-like "#!python" first line
  466.         set unixMode(python) {Pyth}
  467.     }
  468.     # dummy proc to load this mode.  
  469.     proc dummyPython {} {}
  470.     # dummy proc to load the code to make the PythonMenu 
  471.     proc PythonMenu {} {}
  472.     # rest of mode's code follows...
  473.     
  474.     #Lets the automatic comment insertion/continuation
  475.     # routines function with this mode. 
  476.     set Pyth::commentCharacters(General) "\#"
  477.     set Pyth::commentCharacters(Paragraph) [list "## " " ##" " # "]
  478.     set Pyth::commentCharacters(Box) [list "#" 1 "#" 1 "#" 3]
  479.     
  480. The package declaration should contain all code which is necessary to 
  481. recognise a given file as belonging to that mode (hence the use
  482. of 'unixMode' for python), which will then make Alpha call the
  483. dummyProc which will auto-load the entire file.  Other information,
  484. such as the 'commentCharacters' entries above should not go in the
  485. package declaration.
  486.     
  487. Notice that there are two types of 'dummy' proc: each menu Alpha uses
  488. should have a proc of the same name associated with it.  This proc is
  489. called by Alpha _each_ time Alpha tries to insert the menu into the
  490. menubar.  The proc can be empty (as above), or could actually do
  491. something if desired.  The second kind of dummy proc is the 'mode'
  492. dummy proc, given in the 'alpha::mode' command.  Here it is called
  493. 'dummyPython'.  Alpha calls this proc the first time it switches to Pyth
  494. mode.  Again the proc can do something if desired, but will usually
  495. be empty.  If both procs are empty, as above, one can of course
  496. just use one proc (called PythonMenu in this case), and replace the
  497. alpha::mode line by:
  498.  
  499.     alpha::mode Pyth 0.2 PythonMenu {*.py *.pyc *.pyi} PythonMenu
  500.  
  501. The only advantage of this approach is that it saves a small amount
  502. of memory (you can delete the 'dummyPython' proc from the file). Note that 
  503. this only holds true for modes whose Tcl code is in one file.  
  504.     
  505.              Multi-file modes
  506.  
  507. Modes that consist of more than a single file should no longer use a source 
  508. statement that assumes that the other files for the mode will be in 
  509. $HOME:Tcl:Modes.  The best solution is to use Alpha's standard auto-loading 
  510. capability which will source a file when it needs a procedure which is 
  511. contained in that file.  If you must use 'source' manually, you can use 
  512. 'file dirname [procs::find someProcInThisFile]' to get the current 
  513. directory.  Your other files should also be there.
  514.  
  515. A convenient way of implementing your multi-file loading is to create
  516. procs with the same name as the file at the beginning of each file.
  517. Then to load the file you just do 'catch "filename"'.  For example
  518. if there is a proc defined 'proc perl5.tcl {} {}' at the start of
  519. the file "perl5.tcl", then I can auto-load that file by having the 
  520. following code in "perlMode.tcl" (note: actual code differs slightly):
  521.  
  522.     if {[catch perl5.tcl]} { 
  523.         alertnote "Problem loading 'perl5.tcl'" 
  524.     }
  525.  
  526. Remember, you don't necessarily need to source all your mode/pkg's files in 
  527. one go.  Tcl is designed to source files for you when they are needed (when 
  528. a procedure contained in one of them is called).  Hence you only need to 
  529. source files which are required immediately (to set up some data, variables, 
  530. menus etc.)  and not everything else.  It is usually best to have a single 
  531. file which contains all the initialization code, and let any other files be 
  532. auto-loaded as necessary.
  533.  
  534.  
  535.              Use of the term "electric"
  536.  
  537. Through out the documentation and in actual proc names, you will see the use 
  538. of the word "electric", so a note on its usage might be helpful. 
  539. "Electric" is used in the sense of "automatic, power assisted behaviour", it is 
  540. intended to save time, keystrokes, and brainpower. Such behaviour is usually
  541. invoked by certain keystrokes (determined by various preference settings).
  542.  
  543.  
  544.              Mode procs
  545.  
  546. The following procs are either required or desired for a mode to be
  547. fully functional within Alpha.
  548.  
  549. Marking Proc's:        (provide indexes into code via '{}' and "M' pop-ups)
  550.  
  551.     <mode>::parseFuncs   -- (not every mode provides this one)
  552.     <mode>::MarkFile
  553.     
  554. Info providers:        (drive & support access to source or file related info)
  555.  
  556.     <mode>::DblClick    -- usually provides term specific help
  557.     
  558.     <mode>::optionTitlebar    -- provides menu to access related files
  559.     <mode>::optionTitlebarSelect    -- action for menu selection above
  560.     
  561. electric behaviour:    (these assist formatting & and save on keystrokes)
  562.  
  563.     <mode>::carriageReturn    -- this, supported by the following two, help
  564.                             --  to keep indentation standard (indirectly 
  565.                             --  called by a carriage return).
  566.     <mode>::indentLine -- indents a line, usually by calling next proc,
  567.                        -- and then inserting spaces/tabs as appropriate.
  568.     <mode>::correctIndentation -- allows smart-paste package to function
  569.  
  570.   -- These provide electric behaviour for '{', '}', and ';' respectively.
  571.   --  Their use is primarily for languages that use '{' and '}' for code
  572.   --  blocks, and ';' as the line terminator. They are indirectly called 
  573.   --  by the key they correspond to, and then, only if a corresponding mode 
  574.   --  preference flag has been defined and set to one. 
  575.   --                      (see 'Electric braces and semicolons below)
  576.   
  577.     <mode>::electricLeft
  578.     <mode>::electricRight
  579.     <mode>::electricSemi
  580.  
  581. Have a look at a standard mode like Tcl or C++ to see what these
  582. should do.  <mode>::correctIndentation must not fail (the correct
  583. indentation always exists for a line, so Alpha expects the proc to
  584. return a number and not signal an error).
  585.     
  586.              Hooks
  587.  
  588. Do not do all that 'rename saveHook mySaveHook'... stuff.  Use 
  589. 'hook::register' instead. See the file "hook.tcl" for details, but all
  590. you need to do is add lines like these:
  591.  
  592.     hook::register saveHook modified "C" "C++"
  593.     hook::register saveHook modified "Pasc"
  594.     hook::register saveHook htmlLastModified HTML
  595.     hook::register savePostHook codeWarrior_modified "C++" "C"
  596.     hook::register savePostHook ftpPostHook
  597.     hook::register saveasHook htmlLastModified HTML
  598.  
  599. Here's the general form
  600.  
  601.     hook::register 'hook-name' 'your proc' 'mode' ?... 'mode'?
  602.  
  603. If you don't include a 'mode', then your proc will be called no
  604. matter what the current mode is.   Avoid this unless absolutely
  605. necessary.  Here are the current hooks:
  606.  
  607.     activateHook changeMode closeHook deactivateHook modifyModeFlags 
  608.     quitHook resumeHook saveasHook saveHook savePostHook suspendHook
  609.     openHook
  610.  
  611. There's also a 'mode::init' hook which will be called the first
  612. time a mode is started up.  Note that at that time, the mode exists, but its
  613. variables have not yet been made global, and its menus have not
  614. yet been inserted into the menu bar.
  615.  
  616. There's also a 'startupHook' which is called when Alpha starts
  617. up, but after all other initialization has taken place, a 'launch'
  618. hook which is called when Alpha launches another application
  619. (register with hook::register launch yourproc $sig).
  620.  
  621.              Smart mode lines
  622.     
  623. If your mode will want to be able to use the first line of a file to 
  624. determine what mode a file should be opened up in, you need to tell 
  625. alpha what word in the first line should trigger that mode:
  626.     
  627.     set unixMode(python) {Pyth} 
  628.  
  629. A good place to do this is in the body of the your mode's package 
  630. declaration "alpha::mode … {…" statement (see example for Python above).  
  631. Note that the presence of the word itself is not sufficient; it must be of 
  632. the form '#!\usr\..\python' as is common on Unix (where it tells the shell 
  633. with what application to run the script)
  634.  
  635. Note that there is already built in support for opening a file in a given 
  636. mode if the first line contains:
  637.  
  638.     -*-<mode_label>-*-
  639.     
  640. e.g.:
  641.  
  642.     -*-Tcl-*-
  643.  
  644. Also, if the first line contains:
  645.  
  646.     (nowrap)
  647.  
  648. then you will not be asked if you want to see such a file in paragraph 
  649. format simplly because the lines have gotten so long alpha thinks they 
  650. might be from an application that maintains a paragraph as one long line 
  651. and does its own wrapping internally.
  652.  
  653.  
  654.              Mode creator types
  655.     
  656. If your mode wants to declare itself as a default for files with a 
  657. particular creator, (so any file with that creator opens up in that mode) 
  658. you need to tell Alpha with an entry whoses format is like this:
  659.     
  660.     set modeCreator(<4_char_creator_code>) <mode_label>
  661.  
  662. e.g.:
  663.  
  664.     set modeCreator(McPL) Perl
  665.  
  666. A good place to do this is in the body of the your mode's package 
  667. declaration "alpha::mode … {…" statement.
  668.  
  669.              Comment characters
  670.  
  671. If your mode will want to use the standard Alpha comment/uncomment
  672. block procedures, file headers, ... you need to tell Alpha what
  673. characters are used for comments.  Rather than redefining 
  674. the procedure 'commentCharacters', you should just define the following 
  675. variables:
  676.     
  677.     set ${mode}::commentCharacters(General) [list "*" "//"]
  678.     set ${mode}::commentCharacters(Paragraph) [list "/* " " */" " * "]
  679.     set ${mode}::commentCharacters(Box) [list "/*" 2 "*/" 2 "*" 3]
  680.     
  681. where the values shown are for C++ mode.  If you do this then there is
  682. no need to mess with the commentCharacters procedure.  (In general it
  683. is best if your mode does not need to redefine procedures in Alpha's core).
  684.  
  685.              Paragraph definitions
  686.  
  687. Paragraph filling.  You can set the variables:
  688.  
  689.     set ${mode}::startPara {^(.*\{)?[ \t]*$}
  690.     set ${mode}::endPara {^(.*\})?[ \t]*$}
  691.  
  692. to customize your mode's paragraph definition.  The above example's regular 
  693. expressions (third 'word') are for Tcl code.
  694.  
  695. Alpha uses these to determine what it should act on when it is requested to 
  696. re-wrap, make a selection or navigate with respect to paragraphs.  
  697.  
  698. Note that currently the wrapping routines take no notice of code formatting 
  699. rules and are limited utility outside of the 'Text' mode.  The only proc's 
  700. that use these are found in "textFill.tcl".
  701.  
  702.              Electric braces and semicolon
  703.  
  704. If your mode uses electric '{', '}', ';' (i.e. characters that end the 
  705. current line and indent the next one automatically) you need to define 
  706. a few procedures: '${mode}::electricLeft', '${mode}::electricRight' 
  707. and '${mode}::electricSemi' which will be called automatically (you do 
  708. NOT need to bind anything to the keys).  If you do not define these 
  709. procedures, Alpha will use a default electric procedure which works 
  710. pretty well for C, Perl and Java code.
  711.  
  712. Of course the user needs to turn on the electric functionality for
  713. your mode.  (Activate by default by including 'electricBraces' in 
  714. your list of mode features in the alpha::mode command).
  715.  
  716. Do not bind to '{', '}' or ';' if you want these to be electric. Alpha
  717. will automatically call your mode's procedures if they are named
  718. correctly.
  719.  
  720.              Option-click-titlebar menu
  721.  
  722. If your mode has a specific 'opt-titlebar-click' menu, you need to
  723. define the procedures:
  724.     
  725.     proc C++::OptionTitlebar {} {
  726.         # returns list of items for the menu
  727.     }
  728.     proc C++::OptionTitlebarSelect {item} {
  729.         # carries out the mode-specific action when 'item' is selected.
  730.     }
  731.  
  732.              Electric code templates
  733.     
  734. If you mode wants to insert text into the window which contains template 
  735. stops (usually bullets '•' in Alpha), so that the user can move from
  736. one to the next using the standard Alpha template packages (Alpha comes with 
  737. a basic one, and more sophisticated ones build upon the same 
  738. infrastructure), the you should insert template text with:
  739.  
  740.     elec::Insertion "blah blah •• blah blah"
  741.  
  742. This is a simple example with a single template stop.  Template stops are 
  743. noted with a pair of bullets (even though only one appears in the text).  
  744. You can place between the pair of bullets some more information about the 
  745. template stop, for instance:
  746.  
  747.     elec::Insertion "while \{•condition•\} \{\r\t•while body•\r\}\r••"
  748.  
  749. would be useful to insert a typical Tcl 'while' loop.  The template
  750. packages can prompt the user with the explanatory text making code 
  751. entry a little bit easier.
  752.  
  753. The 'elec::Insertion' routine works just like 'insertText' except it treats 
  754. any item •PROMPT• as a template stop called 'PROMPT'.  This procedure takes 
  755. a variable number of arguments, just like 'insertText'.  It has one further 
  756. side-effect.  If there are any stops in the block, then the cursor is 
  757. positioned at the first such stop.  Hence you don't need to do this: set p 
  758. [getPos] ; insertText "blah..."  ; goto $p ; nextTabStop Instead you just do 
  759. 'elec::Insert "blah..."'.  Note that the procedure 'nextTabStop' no longer 
  760. exists.  Use "ring::+", "ring::-" etc.  to move amongst tab stops.  The 
  761. basic Alpha distribution contains only basic template support.  Install 
  762. Vince's Additions to extend this support to persistent stops, with 
  763. user-prompting in the text or status bar,...  You don't have to change your 
  764. code to take advantage of the features of V'sA. It comes for free if you use 
  765. 'elec::Insertion' etc.
  766.  
  767. If you wish to use electric templates, avoid binding anything to the 'tab' 
  768. key or the 'j' key (also opt-tab, cmd-tab,…).  Such bindings may conflict
  769. with the electric bindings.
  770.  
  771. To use electric templates, you'll want to add electricTab to your
  772. list of default mode-features (or you can leave it for the user to
  773. activate).  If your mode never wants the Tab key to indent, then 
  774. define a dummy '<mode>::indentLine' proc which is empty: 
  775. 'proc <mode>::indentLine {} {}'.
  776.  
  777.              Electric return
  778.  
  779. This allows pressing return to indent correctly for the following line 
  780. so you may begin typing immediately.  To use this simply list this 
  781. package in your mode's 'mode-features' list and, do _not_ bind to the 
  782. return key.
  783.  
  784.              Automatic indentation
  785.  
  786. Two variables are associated with a window's indentation scheme: 
  787. 'indentationAmount' and the window's tab-size (which can be read
  788. with 'getWinInfo' or 'text::getTabSize').  If you are writing a custom 
  789. indentation routine, the procedure 'indent::setup' will be useful 
  790. to handle all these choices for you.  Look at the relevant section
  791. of "globals.tcl" to see what that procedure sets up for you.  Most
  792. people user either tab-size = indentation-amount = 4 spaces, OR
  793. tab-size = 8, indentation-amount = 4 spaces.  These cases are quite
  794. different, and it's nice if your mode allows the user to work with
  795. their preferred setup.
  796.  
  797.              The marks menu
  798.  
  799. Each mode has a procedure <mode>::MarkFile which is called to create the
  800. popup 'M' menu of marks.  There is a global flag 'quietlyClearMarks'
  801. which is set to 1 which dictates that the marks should be rebuilt
  802. without prompting the user as necessary.  You can add a mode-pref
  803. to over-ride this if you want.
  804. Just what text-patterns are used to trigger the formation of a 'namedMark' 
  805. (kept in the resource fork), its name, text position and extent, and the 
  806. order in which they are present in the menu, is all determined by the 
  807. <mode>::MarkFile your procedure.
  808.  
  809. For computer language editing modes, the common convention was to create an 
  810. index by routine names for each routine defined in the file, and to present 
  811. it in alphabetical order. The more current convention is to either 
  812. hardwire, or present the user with the option of listing the routine names 
  813. in the order in which they were defined in the file, indented under the 
  814. name of the code section in which it was defined. 
  815.  
  816. The Tcl mode is a good example of the above, by default the defined Tcl 
  817. proc's are presented in alphabetical order.  However if you check the 
  818. 'StucturalMarks' flag in Tcl's mode preferences, you get an index with the 
  819. above format (after regenerating the index via the 'MarkFile' menuitem).  
  820. If you organize your Tcl code into sections of logically or functionally 
  821. related proc's, and then give them a short header by using the 
  822. 'InsertDivider' option under the Tcl Menu, you have an index that can be 
  823. used to quickly get to a procedure when remember its position or 
  824. functionality more than you do its exact name.
  825.  
  826. Of course, it is still often the case that you remember the name and just 
  827. want to get to it quickly via an alphabetical index, so modes that use the 
  828. above scheme usually provide an alphabetical listing via the '{}' popup, 
  829. which is located right above the 'M' popup (see next topic).
  830.  
  831. Power User tip: cmd-clicking anywhere in a window's titlebar (except the 
  832. exact center), or in the "bevel'ed frame" will give you the same menu as 
  833. the 'M' popup. Using the sides of the window lets you access a particular 
  834. area of the menu quicker as you can cmd-click in the approximate location 
  835. of the index you want to go to. Additionally, if the window is flush 
  836. against the lefthand edge of your monitor, it is easier to 'crash' your 
  837. cusor into that edge and summon up the mark menu than it is to hit a eight 
  838. inch square button.
  839.  
  840.              The '{}' popup menu
  841.  
  842. This popup menu can be put to whatever use the mode author wants. If your 
  843. are useing the scheme mentioned in the above section, it is good to use 
  844. this popup to present an alphabetical listing of the routines. Some modes 
  845. add extras such as indicating the number of arguments a routine expects 
  846. (see Tcl), whether a argument is a 'reference' or a 'value' pass (see the 
  847. M2, i.e. modula mode) or anything else that might be useful. Languages that 
  848. use multi-part (qualified) identifiers may name the first part of a group 
  849. of indentifiers and indent the rest of the identifiers that share that 
  850. first part under it.
  851.  
  852. Power user tip: cmd-opt-<K> will put up a listpick dialog of the indexes 
  853. under the '{}' popup, as this is usually alphabetical you can type the 
  854. starting letters of the index you want to go to. (note: see 'Emacs Help' 
  855. for some other tips to navigate any scrolling list dialog box.)
  856.  
  857.  
  858.  
  859.              <mode>Completions.tcl
  860.  
  861. Each mode can have a completions file for use by the 'elecCompletions' 
  862. package (part of Vince's Additions or available separately).  To use
  863. this, place the appropriate definitions in a file called 
  864. '<mode>Completions.tcl'.  The installer will place such files in the 
  865. 'Completions' directory automatically (provided you don't put them in 
  866. a sub-folder of your distribution), and they will also be sourced
  867. automatically the first time a file opens in your mode.  There is
  868. therefore no need for you to source the file yourself.
  869.  
  870. ===============================================================================
  871.  
  872.            Writing new menus
  873.  
  874. New menus are placed in ":Tcl:Menus", and contain a start-up
  875. section of much the same form as a mode or feature:
  876.  
  877.     alpha::menu ftpMenu    0.3 global "•141" {
  878.         # One-time initialisation script 
  879.         
  880.         # here we do nothing
  881.     } {
  882.         # Activation script
  883.         
  884.         # here we do the standard thing of calling the menu proc
  885.         ftpMenu
  886.     } {
  887.         # Deactivation script
  888.     }
  889.     # proc ftpMenu to auto-load
  890.     proc ftpMenu {} {}
  891.  
  892. The 'global' parameter tells Alpha that this menu isn't associated with
  893. any particular mode (otherwise you can replace 'global' by a list of 
  894. modes possibly including the global keyword, e.g. {global WWW HTML}).
  895.  
  896. Older versions of Alpha used to call a procedure with the same name
  897. as the menu (here 'ftpMenu') automatically whenever the menu was to
  898. be inserted.  The newer setup is a bit more verbose, but puts more
  899. control in your hands.
  900.  
  901. NOTE: If all you want to do is add a submenu to an already existing
  902. menu, go to the section 'Adding Items to Global Menus': you don't
  903. need the 'alpha::menu' statement, but actually need to write a 
  904. feature using 'alpha::feature'.
  905.  
  906. A menu-package is a set of code which builds and handles a standalone menu 
  907. which the user may choose as a global menu.  Examples are the ftpMenu, 
  908. filesetMenu, voodooMenu, internetConfigMenu, colorMenu and eudoraMenu (in 
  909. fact this last item, since it has a mode associated with it, could in fact 
  910. be rewritten as a mode with attached menu).  
  911.  
  912. Note: as of Alpha 7.1, you should use the command 'Menu -n ...' to build 
  913. menus, not 'menu -n ...'
  914. ===============================================================================
  915.  
  916.            Writing new features or extensions
  917.  
  918. An extension is a package which can be turned on once and then left 
  919. alone.  Something which requires turning on/off for different modes is 
  920. a feature.  In fact an extension is just implemented as a simple form 
  921. of feature.  A new extension must provide at the very least the 
  922. following line, preferably as the first non-comment line of one of its 
  923. files:
  924.  
  925.     alpha::extension 'NAME' 'VERSION'
  926.     
  927. It is better, if possible, if the extension can provide a small script to 
  928. carry out initialisation (which occurs when Alpha starts up, if the user
  929. has turned the package on).  If provided Alpha will use that script 
  930. rather than sourcing the entire extension file.  This means Alpha will
  931. start up more quickly.  Such a script is given by the following line:
  932.  
  933.     alpha::extension 'NAME' 'VERSION' 'SCRIPT'
  934.     
  935. A feature is more sophisticated and takes arguments of the following 
  936. form:
  937.  
  938.     alpha::feature 'NAME' 'VERSION' 'LIST OF MODES/GLOBAL' \
  939.       'INIT SCRIPT' 'ACTIVATE SCRIPT' 'DEACTIVATE SCRIPT'
  940.     
  941. Here is an example from the 'bibtexEngine' package:
  942.  
  943.     alpha::extension bibtexEngine 1.8 {
  944.         eventHandler GURL GURL GURLHandler
  945.     }
  946.  
  947. Here we didn't bother to turn the feature on and off, since its 
  948. initialisation was so trivial, and it won't interfere with other 
  949. modes at all.  Here's a more complex example:
  950.  
  951.     alpha::feature latexMathbb 1.0 {TeX Bib} {
  952.         newPref variable blackboardBoldSymbols "QZRN" TeX TeX::adjustMathbb
  953.         hook::register mode::init TeX::adjustMathbb TeX
  954.     } "" ""
  955.  
  956. We didn't bother with activation deactivation, since the definitions 
  957. don't take effect in other modes.  The simple 'extension' and 
  958. 'feature' commands make it very, very easy to extend Alpha's 
  959. functionality without messing with the user's preferences file, 
  960. without creating any '...+.tcl' extension files and without a complex 
  961. installation process.  Alpha simply maintains a database of all 
  962. 'extension' scripts, and evaluates at startup all scripts for 
  963. extensions which the user has activated.
  964.  
  965.            Writing new extensions (keyboard caveats)
  966.  
  967. Writers of any package for Alpha should pay some attention to the 
  968. problems which can arise with international keyboards.  Some bindings
  969. are simply not available on some keyboards.  For instance, on some
  970. keyboards, you need to use 'shift' to get the key '\' (unlike 
  971. american keyboards where it is a single keypress).  On such a keyboard
  972. there is no distinction between 'cmd-\' and 'shift-cmd-\'.  There is
  973. no simple workaround for this problem.
  974.  
  975. Possibilities are: (i) check the current keyboard definition and adjust
  976. bindings appropriately (based upon user feedback, presumably). (ii) let
  977. the bindings be user-definable either by using 'newPref binding' to
  978. define things, or by using a menu-scheme such as is used by HTML mode.
  979.  
  980.            Technicalities of different menu/feature/extensions
  981.  
  982. Menus and features and extensions are all treated in the same way by
  983. Alpha.  However each will have different associated information which
  984. will determine whether/in what section it appears in a dialog box.
  985. All this information is stored in the index::feature array.  
  986.  
  987. ...to be continued...
  988.  
  989. ===============================================================================
  990.            
  991.            Package preferences
  992.  
  993. Alpha stores preferences in three different places:
  994.  
  995. 1)    Global preferences are stored in the global->preferences menu, and
  996. are for variables/flags which maintain a value at the global scope.
  997.  
  998. 2)  Mode preferences are stored in the mode->preferences… item, and
  999. are for variables/flags which are stored in a mode array, but are transfered 
  1000. into global scope when that mode is active (and hence temporarily override 
  1001. any global preferences with the same names)
  1002.  
  1003. 3)  Packages may add to the global/mode preferences as they desire.  They 
  1004. may also store preferences in their package array '${pkg}modeVars(…)'.  Such
  1005. variables/flags are never transfered into the global scope.  Menu items to 
  1006. edit a package's preferences should be placed in the 'global' menu, unless 
  1007. they are global/mode prefs which should be added to Alpha's default 
  1008. routines for use by the standard Alpha dialogs.  There is a standard proc
  1009.  
  1010.     package::addPrefsDialog Mypkg
  1011.     
  1012. which you can use to add an item to the global menu which will bring
  1013. up the standard dialog to edit the contents of your '${pkg}modeVars(…)'
  1014. array.
  1015.  
  1016.              Adding to the core prefs dialogs
  1017.  
  1018. If you wish to add items to any of the core preferences pages (Backups,
  1019. Electric, Miscellaneous,...), you can do that like this:
  1020.  
  1021.     lunion varPrefs(Electric) var1 var2
  1022.     lunion flagPrefs(Electric) flag1 flag2
  1023.  
  1024. All non-registered global preferences are added to the Miscellaneous page,
  1025. so there is no need to do that automatically.  Make sure you don't add
  1026. too much to any of these pages, because they will become too large to
  1027. display correctly!
  1028.  
  1029. You can also add new core preferences pages.  All you have to do is create
  1030. a new 'flagPrefs' entry (Alpha uses the command 'array names flagPrefs' to
  1031. list the different pages):
  1032.  
  1033.     lunion flagPrefs(NewPage) flag1
  1034.     
  1035. Only add such pages if your package really does merit it; otherwise you're 
  1036. better off just add a new global preferences dialog in the global menu.
  1037.     
  1038.              Defining a package's flags and variables
  1039.  
  1040. Preferences for a mode or package are defined as follows:
  1041.  
  1042.     # description of the preference
  1043.     newPref type name {val 0} {pkg "global"} {pname ""} \
  1044.         {options ""} {subopt ""}
  1045.  
  1046. Define a new preference variable/flag.
  1047.  
  1048. 'type' is one of:
  1049.   'flag' (on/off only), 'variable' (anything), 'binding' (key-combo)
  1050.   'menubinding' (key-combo which works in a menu), 'file' (input only),
  1051.   'io-file' (either input or output), 'funnyChars'
  1052.   
  1053. 'name' is the var name, 
  1054.  
  1055. 'val' is its default value (which will be ignored if the variable
  1056. already has a value)
  1057.  
  1058. 'pkg' is either 'global' to mean a global preference, or the name 
  1059. of the mode or package (no spaces) for which this is a preference.
  1060.  
  1061. 'pname' is a procedure to call if this preference is changed by
  1062. the user (no need to setup a trace).  This proc is only called
  1063. for changes made through prefs dialogs or prefs menus created by
  1064. Alpha's core procs.  Other changes are not traced.
  1065.  
  1066. Depending on the previous values, there are two optional arguments
  1067. with the following uses:
  1068.  
  1069. TYPE:
  1070.  
  1071. variable:
  1072.  
  1073. 'options' is a list of items from which this preference takes a single
  1074. item.
  1075. 'subopt' is any of 'item', 'index', 'varitem' or 'varindex' or 'array', where
  1076. 'item' indicates the pref is simply an item from the given list
  1077. of items, 'index' indicates it is an index into that list, and
  1078. 'var*' indicates 'items' is in fact the name of a global variable
  1079. which contains the list. 'array' means take one of the values from an array.
  1080. If no value is given, 'item' is the default
  1081.  
  1082. binding:
  1083.  
  1084. 'options' is the name of a proc to which this item should be bound.
  1085. If options = '1', then we bind to the proc with the same name as
  1086. this variable.  Otherwise we do not perform automatic bindings.
  1087.  
  1088. 'subopt' indicates whether the binding is mode-specific or global.
  1089. It should either be 'global' or the name of a mode.  If not given,
  1090. it defaults to 'global' for all non-modes, and to mode-specific for
  1091. all packages.  (Alpha tests if something is a mode by the existence
  1092. of modeMenus($mode))
  1093.  
  1094. menubinding:
  1095.  
  1096. menubindings are like bindings, but they don't have any automatic
  1097. binding capabilities, and are restricted to key-sequences which the
  1098. MacOS allows in menus.  Here is an example of how one might declare
  1099. the 'QuickFind(Regexp)' dynamic pair using a menubinding pref:
  1100.  
  1101. declare the binding:
  1102.  
  1103.     «Alpha ƒ» newPref menubinding quickFind/quickFindRegexp <B/S
  1104.     
  1105. edit it if we like with:
  1106.  
  1107.     «Alpha ƒ» dialog::getAKey quickFind/quickFindRegexp <B/S
  1108.     
  1109. show the menu sequence if we like:
  1110.     
  1111.     «Alpha ƒ» menu::bind quickFind/quickFindRegexp -
  1112.     <S<E<B/SquickFind <S<I<B/SquickFindRegexp
  1113.     «Alpha ƒ» 
  1114.  
  1115. add it to a menu:
  1116.  
  1117.     «Alpha ƒ» eval menu::insert Search items end \
  1118.         [menu::bind quickFind/quickFindRegexp -]
  1119.     
  1120. Have a look at the search menu.  It has a new dynamic item at the bottom!
  1121.  
  1122. funnyChars:
  1123.  
  1124. This is like 'variable', but provides for automatic decoding/encoding 
  1125. of tab, newline, carriage return into \t, \n, \r when the value is
  1126. displayed to the user.
  1127.  
  1128. Note that if you place a comment (one or more lines) just before the
  1129. 'newPref' statement, it is scanned and stored by Alpha in a cache.  It
  1130. can then be used to explain to the user what each preference does when
  1131. the user selects 'describe mode' or presses the 'Help' button in a 
  1132. preference dialog.
  1133.  
  1134.            Declaring help text for your preferences
  1135.  
  1136. Alpha has the ability to extract descriptive text for your preference
  1137. items automatically, provided they are declared using 'newPref', and
  1138. that you follow these guidelines.
  1139.  
  1140. If there is a comment (a line starting with '#') on the line/lines 
  1141. preceding the newPref command, Alpha will (when it rebuilds the package 
  1142. indices) store the text in that line/lines and use it to display helpful 
  1143. information for that preference.  For example if you hit the 'help' button 
  1144. in a dialog, Alpha will display this information.  Furthermore, in the 
  1145. forthcoming Alpha 8.0, this information will be used for balloon help in 
  1146. the prefs dialog related to your package/mode, provided you use the 
  1147. standard mechanisms for declaring your mode/menu/feature/extension and you 
  1148. use the standard preference mechanism supplied.  The format of the comment
  1149. lines is simple for all except basic flags (newPref flag ...).  These will 
  1150. display a different help text in balloons depending on their state.  There 
  1151. are four possible states, although Alpha only really uses the first and 
  1152. third such states at present.  The first state is the 'unchecked' state, 
  1153. and the third the 'checked' state.  You declare separate help text for the 
  1154. four possible states like this:
  1155.  
  1156.     # it is unchecked|it is dimmed|it is checked|it is checked and dimmed
  1157.     newPref flag myFlag ...
  1158.  
  1159. In fact all help items have four possible states, although you will 
  1160. usually not notice the other possibilities.  As you can see, Alpha uses '|' 
  1161. to separate the different pieces of text.  Currently a typical help text 
  1162. for a checkbox item should probably just look like this: 
  1163.  
  1164.     # To use a solid rectangular cursor, click this box||To use a thin 
  1165.     # vertical cursor, click this box.
  1166.     newPref flag blockCursor 0
  1167.  
  1168. Notice the syntax of the two messages.  Apple's interface guidelines
  1169. give some advice for balloon help which you should follow for two 
  1170. reasons: first, it's good advice for writing balloons, and second,
  1171. Alpha assumes your messages are of the above form to use the text
  1172. effectively both for balloons, and for descriptive text.  Alpha will
  1173. automatically convert the above to:
  1174.  
  1175.     Block Cursor: To use a solid rectangular cursor, turn this item on.  To
  1176.     use a thin vertical cursor, turn this item off.
  1177.  
  1178. which is used in the descriptive dialogs Alpha sometimes provides.  This 
  1179. advice is of greatest importance for 'flag' preference items, since they
  1180. require two separate on/off balloon help texts.  Other items currently
  1181. just expect one piece of text.  Each text item should be no longer than
  1182. 255 characters.  The simplest balloon help methods impose this constraint
  1183. (in principle it could be relaxed, by using the more complex help methods
  1184. inside Alpha, but it doesn't seem necessary).
  1185.  
  1186. A similar mechanism will soon be available for menus.
  1187.     
  1188.            Adding items to global menus
  1189.  
  1190. Using 'addMenuItem' is a bad idea, since many menus are dynamically
  1191. rebuilt and such items will be lost.  Furthermore, addMenuItem does
  1192. not work if you want to add dynamic items or sub-menus.  Also
  1193. creating a menu directly using 'Menu -n Name {list of items}' is
  1194. generally a bad thing to do when using Alpha version 7.0 or newer.
  1195.  
  1196. The solution to these problems is to use the following calls:
  1197.  
  1198.     menu::buildProc 'nameOfMenu' 'nameOfIts_build-proc' 
  1199.     menu::insert 'nameOfMenu' 'type' 'where' 'menuItem' ?menuItem...?
  1200.  
  1201. For technical reasons, if you use both types of call, always add the procs 
  1202. first.  You can add any list of menuItems using the latter of these two calls.  
  1203. The first registers a procedure which will be called to build a given menu.
  1204.  
  1205. Menus must be rewritten to support this new feature.  Currently all 
  1206. global menus File...Config support it, and several modes: Tcl, Perl, 
  1207. TeX.
  1208.  
  1209.              menu::buildProc
  1210.  
  1211. This proc registers a procedure to be the 'build-proc' for a given menu 
  1212. (tech note: just adds the build-proc to the "menu_build_procs" global array 
  1213. with the given menu's name as its index).  The build-proc procedure can do 
  1214. one of two things:
  1215.  
  1216. i) build the entire menu, including evaluating the 'Menu ...' command.
  1217. In this case the build proc should return anything which doesn't
  1218. begin 'build ...'  
  1219.  
  1220. If the proc returns anything beginning with 'Menu ..' that returned 
  1221. string is evaluated, but no insertions can take place.
  1222.  
  1223. ii) build up part of the menu, and then allow pre-registered menu
  1224. insertions/replacements to take-effect.  In this case the procedure
  1225. should return a list of the following (listed by index in the list):
  1226.  
  1227. 0: "build"
  1228. 1: list-of-items-in-the-menu
  1229. 2: menu procedure to call when an item is selected.  If nothing is given,
  1230. or if '-1' is given, then we don't have a procedure.  If "" is given,
  1231. we use the standard 'menu::generalProc' procedure.  Else we use the
  1232. given procedure.
  1233. 3: list of submenus which need building.
  1234. 4: over-ride for the name of the menu.
  1235.  
  1236. Here is an example of what gets returned by "menu::globalBuild", the 
  1237. build-proc for the menu named "global" (see Config:Global:):
  1238.  
  1239.         «Alpha ƒ» menu::globalBuild
  1240.         0:    build 
  1241.         1:    {
  1242.                 /p<U<BmenusAndFeatures… 
  1243.                             {Menu -n preferences {}} 
  1244.                 editPrefsFile 
  1245.                 (- 
  1246.                 compareWindowsPrefs… 
  1247.                 newDocumentPrefs… 
  1248.                 (- 
  1249.                 specialKeys… 
  1250.                 listGlobalBindings 
  1251.                 listPackages 
  1252.                 listAllBindings 
  1253.                 listFunctions 
  1254.                 (- 
  1255.                 rebuildPackageIndices
  1256.             } 
  1257.         2:    menu::globalProc 
  1258.         3:    preferences
  1259.         
  1260.         Note: the above output was reformated and numbered to make its structure 
  1261.         explicit, also note that any additions to what you see in 'Config:Global:' 
  1262.         are due to calls to "menu::insert".
  1263.  
  1264. You must register the build-proc before attempting to build the menu (i.e. 
  1265. call menu::buildProc.  
  1266.  
  1267. Once registered, any call of 'menu::buildSome <name of your menu>' will 
  1268. build your menu.
  1269.  
  1270.              menu::insert
  1271.  
  1272. nameOfMenu, type, where, then list of menuItems.  Here, type can be, either 
  1273. 'items', or 'submenu'.
  1274.  
  1275. Add given items to a given menu, provided they are not already there.
  1276. Rebuild that menu if necessary.
  1277.  
  1278. There are also procs 'menu::removeFrom' which does the opposite of
  1279. this one, and 'menu::replaceWith' which replaces a given menu item
  1280. with others.
  1281.  
  1282. There is a difference between 'menu::insert Utils submenu 2 compare' and 
  1283. 'menu::insert Utils items 2 [list Menu -n compare {}]'.  The former 
  1284. registers the submenu as a submenu which will be built automatically by a 
  1285. call to 'menu::buildSome' each time the parent menu is rebuilt, the latter 
  1286. does no such thing.  You will, therefore normally wish to use the first 
  1287. form, but occasionally there will be situations when the latter would be 
  1288. better.
  1289.  
  1290. Here is a simple example:
  1291.  
  1292.     alpha::extension compareWindows 0.1 {
  1293.         Bind 0x32    <X> compare::windowsInPlace
  1294.         Bind '1'  <X> compareOpt
  1295.         Bind 0x32    <sX> compareNext
  1296.         Bind 0x12    <sX> compareOptNext
  1297.         menu::insert Utils submenu 2 compare
  1298.         menu::insert "compare" items end windowsInPlace
  1299.     }
  1300.  
  1301. We first add a submenu after the second item in the Utils menu, called
  1302. 'compare', and then add to the end of that compare menu. This code works 
  1303. whether the package is active at startup or not.  Here is a more 
  1304. complex example:
  1305.  
  1306.     alpha::extension documentProjects 1.2 {
  1307.         alpha::package require elecCompletions
  1308.         alpha::package require newDocument
  1309.         menu::buildProc "Current Project" Docproj::currentMenu
  1310.         menu::insert global items end \
  1311.             "documentProjectPrefs…" "userDetails…" \
  1312.             "<E<SremoveDocumentTemplate…" "<S<BeditDocumentTemplate…" \
  1313.             "<SnewDocumentTemplate…" \
  1314.             "<E<SremoveProject…" "<S<BeditProject…" "<SnewProject…"
  1315.         menu::insert global submenu end {Current Project}
  1316.         newPref binding updateFileVersion "/f<U" Docproj
  1317.         menu::insert fileUtils items end \
  1318.             "showInFinder" \
  1319.             "(-" \
  1320.             "updateDate" \
  1321.             "[menu::bind DocprojmodeVars(updateFileVersion) -]"
  1322.         lunion elec::MenuTemplates "createHeader" "newDocument"
  1323.         menu::insert elec items end \
  1324.             {Menu -n functionComments -p menu::fileUtils {
  1325.             "/efunctionComment"    
  1326.             "/e<IfunctionCommentSimple" 
  1327.             "/e<OfunctionCommentWithAuthor" 
  1328.             "/e<UfunctionCommentUpdate" 
  1329.         }}
  1330.         set newDocument::handlers(documentProjects) Docproj::newHandler
  1331.     }
  1332.  
  1333. The 'documentProjects' package adds items to many different menus,
  1334. including the 'elec' menu (from the elecCompletions package).
  1335.  
  1336. ===============================================================================
  1337.  
  1338.            Package testing
  1339.  
  1340. The 'alpha::package' command is very similar to Tcl 8.0's standard
  1341. 'package' command, but differs in a few respects.  When Alpha upgrades
  1342. to Tcl 8, this will allow both features to coexist happily.  You can use
  1343. 'alpha::package' to check/request the presence of other packages.
  1344.  
  1345.     alpha::package require NAME ?VERSION?
  1346.     
  1347. Other sub-commands are 'exists' 'names' 'versions' 'vcompare' 'vsatisfies'
  1348. 'forget' 'uninstall' and 'mode', 'menu' and 'package'.  These last three
  1349. mimic the usual alpha::mode alpha::menu and alpha::package commands.
  1350.  
  1351.     alpha::package require ?-extension -mode -menu? name version
  1352.     alpha::package exists ?-extension -mode -menu? name version
  1353.     alpha::package names
  1354.     alpha::package uninstall name version [this-file|this-directory|script]
  1355.     alpha::package vcompare v1 v2
  1356.     alpha::package vsatisfies v1 v2
  1357.     alpha::package versions ?-extension -mode -menu? name
  1358.     alpha::package type name
  1359.     alpha::package info name
  1360.     alpha::package maintainer name version {name email web-page}
  1361.     alpha::package help name version [file 'name'|text]
  1362.  
  1363. Equivalent to alpha::mode, alpha::menu and alpha::extension
  1364.  
  1365.     alpha::package mode ...
  1366.     alpha::package menu ...
  1367.     alpha::package extension ...
  1368.  
  1369. For extensions only:
  1370.  
  1371.     alpha::package forget name version
  1372.  
  1373. ..
  1374.  
  1375. ===============================================================================
  1376.  
  1377.            Installation
  1378.  
  1379. There is a new install mode 'Inst' which adds the Install menu.
  1380. Install mode is trigerred when a file's name ends in 'Install'
  1381. or 'INSTALL', or when the first line of the file contains the
  1382. letters 'install', provided in this last case, that the file
  1383. is not in Alpha's Tcl hierarchy.  This last case is useful so
  1384. that a single .tcl file can be a package and be installed by
  1385. Alpha using these nice scripts, without the need for a separate
  1386. install-script-file.  However once that .tcl file is installed,
  1387. if you open it you certainly wouldn't want it opened in Install mode!
  1388.     
  1389. So, single file packages should just include 'install' somewhere in
  1390. their first line.  Multi-file packages should include an install
  1391. file.  Call this file 'OPEN.TO.INSTALL' or something like that.
  1392. When the user opens it, Inst mode is activated, and the user can
  1393. use the install menu to install your package.  If you wish the
  1394. installation dialog to be activated automatically, include the
  1395. text (auto-install) in the first line of the file.
  1396.  
  1397. Most packages will _not_ need anything other than the existence of
  1398. such a file.  In fact a file called 'OPEN.TO.INSTALL' containing the
  1399. single line '(auto-install)' will do the trick nicely.
  1400.  
  1401. Alpha will scan the installation file directory and make a nice
  1402. dialog with 'Easy install' and 'Custom install' options.  Alpha
  1403. knows where Modes, Menus, Completions, Bug fixes, Tools, Packages,
  1404. Extensions, ... all go in the Alpha hierarchy.
  1405.  
  1406. In summary:
  1407.  
  1408. (1) If it's a single file package (e.g. smartPaste.tcl), simply include
  1409. '(auto-install)' in the first line of the file, and when the file is
  1410. opened Alpha will try to install it.
  1411.  
  1412. (2) If it's a multi-file package, create a file 'OPEN.TO.INSTALL'
  1413. containing a single line containing the text '(auto-install)' and place it
  1414. in the same directory as your other files.  When the user opens that file,
  1415. they'll get a nice installation dialog.  (You can also change its type to
  1416. 'InSt' if you have resedit to get a nice icon).
  1417.  
  1418. More sophisticated things are possible, but usually not needed.  Note that
  1419. if you want to read an install file, rather than execute it, hold down
  1420. 'option' when you double click on it.
  1421.  
  1422. Finally, in most cases, simply dropping files into Alpha's directory
  1423. hierarchy will work (and Alpha will notice they are there and rebuild
  1424. indices etc automatically).  However if a user is upgrading, rather than
  1425. installing such a package for the first time, Alpha will not notice the
  1426. change and not rebuild indices and this will probably cause problems.  
  1427. Hence this is not a recommended installation technique.
  1428.  
  1429.              Package-specific installation over-rides
  1430.  
  1431. You can over-ride the default behaviour by providing a 'xxx_install.tcl'
  1432. file in the file directory.  In such a case that file will be sourced.
  1433. See "install.tcl" for some more information on how to over-ride the
  1434. default behaviour.  You will usually use the following procedure:
  1435.  
  1436.     install::packageInstallationDialog 'NAME' 'DESCRIPTION' ...
  1437.  
  1438. Optional arguments are as follows:
  1439.  
  1440.     -ignore {list of files to ignore}
  1441.     -remove {list of files to remove from Alpha hierarchy}    
  1442.     -forcequit '0 or 1'  
  1443.         (forces the user to quit; default 0)
  1444.     -require {Pkg version Pkg version …}
  1445.         e.g. -require {Alpha 7.0b1p2 elecCompletions 7.99}
  1446.     -provide {Pkg version Pkg version …}
  1447.  
  1448. and 
  1449.  
  1450.     -SystemCode -Modes -Menus -BugFixes -Completions -Packages
  1451.     -ExtensionsCode -UserModifications -Tools -Home
  1452.  
  1453. which force the placement/use of the following lists of files.  To
  1454. require an exact package version use:
  1455.  
  1456.     -require {Alpha {-exact 7.0b2} elecCompletions {-exact 8.1.2} ...}
  1457.  
  1458. Also, rather than having separate 'OPEN.TO.INSTALL' and '*install.tcl'
  1459. files, if the former file contains the text 'auto-install-script' in
  1460. its first line, it will be used as a Tcl script, and sourced rather than
  1461. opened.  Ensure that first line begins with a '#' or an error will
  1462. result.  (You can open that file for editing, without triggering the
  1463. install script if you hold down a modifier key).
  1464.  
  1465. If you gave the -provide option, Alpha checks those items with what
  1466. the user has already installed and warns if an item has already been 
  1467. installed and is not older than the one about to be installed.
  1468.  
  1469. The '-forcequit' option may also take '2' as an argument, but this
  1470. is only used to update Alpha's core code: do not use this for your
  1471. own packages, since Alpha will not update the package indices
  1472. correctly.
  1473.  
  1474.              Uninstalling packages
  1475.  
  1476. Each package should provide a 'alpha::package uninstall name version script' 
  1477. statement.  When your script is evaluated, the global variable 'pkg_file' 
  1478. will be initialised to the full name of the file which contains the 
  1479. uninstall command.  Therefore for a single file package, the following is 
  1480. normal:
  1481.  
  1482.     alpha::package uninstall developerUtilities 1.1 {file delete $pkg_file}
  1483.  
  1484. However, a much more convenient form of the above command is also possible, 
  1485. and most packages use it --- you may combine declaration and uninstall lines 
  1486. like this:
  1487.  
  1488.     alpha::extension developerUtilities 1.1 {
  1489.         # declaration script
  1490.     } uninstall {
  1491.         # uninstall script
  1492.     }
  1493.     
  1494. i.e. there are two extra optional arguments to the 'package' command.
  1495. Finally to be even simpler, if the command is 'uninstall this-file',
  1496. then that is equivalent to {file delete $pkg_file}, and if the command
  1497. is 'uninstall this-directory', then that entire file's directory is
  1498. removed.  Make sure you don't use 'uninstall this-directory' for a
  1499. single-file package, or you'll wipe out the entire package hierarchy.
  1500. Similarly alpha::mode and alpha::menu commands may contain an optional
  1501. uninstall script like the above.
  1502.  
  1503.              Disabling packages
  1504.  
  1505. A package can add a script to be evaluated when the user disables the
  1506. package.  You do that with the additional command 'disable':
  1507.  
  1508.     alpha::extension developerUtilities 1.1 {
  1509.         # declaration script
  1510.     } disable {
  1511.         # disable script
  1512.     }
  1513.  
  1514. Complex packages will probably not provide such a script.  In such a
  1515. case the user would have to restart Alpha to disable the package
  1516. correctly.
  1517.  
  1518.              Tcl index files
  1519.  
  1520. You probably know that Tcl uses 'index' files to find procedures which
  1521. are called but not yet defined.  Your installation directories may
  1522. contain index files if you desire, but they are only installed if no
  1523. current index file exists in the installation location.  You cannot
  1524. override this behaviour.
  1525.  
  1526. ===============================================================================
  1527.            
  1528.            Vince's Additions Support:
  1529.  
  1530. This is primarily for new modes.  Please note "Vince's Additions" is
  1531. largely a historical term now.  It refered to a large package of 
  1532. extensions to Alpha 6.x which have gradually turned into the following
  1533. packages: better templates, new document, electric bindings, electric
  1534. completions, mode search paths, function comments, developer utilities,
  1535. electric menu, plus some others!  This section simply shows how you
  1536. can make your mode/menu/extension aware of these other packages,
  1537. so that their functionality can be used effectively.
  1538.  
  1539.              Source-Header files
  1540.      
  1541. If your mode makes distinctions between 'Source' and 'Header' 
  1542. files, you should define these two variables
  1543.  
  1544.     newPref var sourceSuffices { .cc .cp .cpp .c .icc } C++
  1545.     newPref var headerSuffices { .h .hh } C++
  1546.  
  1547.              Completions
  1548.  
  1549. If you mode is to use a variety of completion routines, define
  1550. an array entry like this:
  1551.  
  1552.     set completions(${mode}) \
  1553.         {completion::cmd completion::electric completion::word}
  1554.  
  1555. For the meaning of the list items, look at "elecCompletion.tcl".  If
  1556. all you need is the basic 'Command', 'Electric' and 'Word' completion
  1557. routines, the above list will do the trick.  You will then need to
  1558. define a variable ${mode}cmds like this:  
  1559.  
  1560.     set Ccmds { #elseif #endif #include class default enum for register return 
  1561.      struct switch typedef volatile while }
  1562.  
  1563. It MUST be in alphabetical order.  For electric template insertions, you need
  1564. to create an array with entries like these:
  1565.     
  1566.     set Celectrics(for) " (•init•;•test•;•increment•)\{\n\t•loop body•\n\}\n••"
  1567.     set Celectrics(while) " (•test•)\{\n\t•loop body•\n\}\n••"
  1568.     set Celectrics(switch) " (•value•)\{\n…case •item•:\n\t•case body•\n…default:\n\t•default body•\n\}\n••"
  1569.     set Celectrics(case) " •item•:\n…•case body•\ncase"
  1570.  
  1571.              Mode-specific completions
  1572.  
  1573. If your mode has its own completion routines, they must be named
  1574. ${mode}::Completion::Type, where 'Type' is an entry in the above
  1575. list.  You'll have to know a reasonable bit of Tcl to write your
  1576. own routines like that.  Look at C::Completion::Class for a relatively
  1577. simple example.
  1578.  
  1579.              Electric menu templates
  1580.  
  1581. ${mode}Templates is a list of names which are added to the electric 
  1582. menu's 'Templates' sub-menu.  The real procs should be called 
  1583. 'file::${name}'.
  1584.  
  1585.              Vince's Additions summary
  1586.  
  1587. That's it!  Take a look at "scilabMode.tcl" as a simple example of a new mode
  1588. which makes use of Vince's Additions.
  1589.  
  1590. ===============================================================================
  1591.  
  1592.